import { Props, Key, Ref, ReactElementType, Wakeable } from 'shared/ReactTypes';
import {
	ContextProvider,
	Fragment,
	FunctionComponent,
	HostComponent,
	WorkTag,
	SuspenseComponent,
	OffscreenComponent,
	LazyComponent,
	MemoComponent
} from './workTags';
import { Flags, NoFlags } from './fiberFlags';
import { Container } from '../../react-dom/src/hostConfig'; // 因为有不用环境 所以这个不能写死
import { Lane, Lanes, NoLane, NoLanes } from './fiberLanes';
import { Effect } from './fiberHooks';
import { CallbackNode } from 'scheduler';
import {
	REACT_MEMO_TYPE,
	REACT_PROVIDER_TYPE,
	REACT_LAZY_TYPE,
	REACT_SUSPENSE_TYPE
} from 'shared/ReactSymbols';
import { ContextItem } from './fiberContext';

interface FiberDependencies<Value> {
	firstContext: ContextItem<Value> | null;
	lanes: Lanes;
}

// <div id="oDiv" className="test">
// <div>23</div>
// <span>111</span>
// 1111
// </div>
// 生成的 reactElement 大概元素结构

// const a = {
//   $$typeof: Symbol('react.transitional.element'),
// key: null,
// props:{id: 'oDiv', className: 'test', children: [
//   a,a,a
// ]},
// type: "div",
// _owner: null,
// _store: {validated: 0},
// ref: null,
// }

// <div id="oDiv" className="test">
// <div>23</div>
// </div>
// 生成的 reactElement 大概元素结构

// const a = {
//   $$typeof: Symbol('react.transitional.element'),
// key: null,
// props:{id: 'oDiv', className: 'test', children:a},
// type: "div",
// _owner: null,
// _store: {validated: 0},
// ref: null,
// }

export class FiberNode {
	type: any;
	tag: WorkTag;
	key: Key | null;
	stateNode: any;
	ref: Ref | null;

	// 构成树状结构
	return: FiberNode | null;
	sibling: FiberNode | null;
	child: FiberNode | null;
	index: number;

	// 作为工作单元
	memoizedProps: Props | null; // momeizedProps 是 当前fiber beginWork阶段结束后 pendingProps 赋值给 memoizedProps

	pendingProps: Props; // pendingProps 是当前fiber 正在beginWork阶段使用的props pendingProps用于去创建 当前fiber的子fiber
	//pendingProps：对于 HostText pendingProps 里面的content 就是文本
	// 对于 fragment pendingProps 就是子 react 元素和 react 元素 数组
	// 对应 函数组件来说pendingProps 就是 函数组件的参数
	// 对应 divHostComponent 这种来说  pendingProps.children 就是 div 里面的 react 元素 或数组
	// 可以拿babel 官网 生产对应的jsx查看

	memoizedState: any; //更新完成后的 state  函数组件 memoizedState 指向的是hooks链表的第一个hook  如果是 hostRootFiber 指向的是 app对应的 reactElement 元素

	// 双缓存
	alternate: FiberNode | null;

	// 副作用
	flags: Flags;

	// 存放 所以子fiber 中的 所以类型副作用flags 如果每个位上都是1代表 增删改移 都存在
	// 那么后续只需要 判断 subtreeFlags 就可以知道子fiber 有没有副作用操作 就不需要一个个遍历了
	subtreeFlags: Flags;

	// 消费更新  存储着 更新
	updateQueue: unknown;

	// 更新阶段 需要删除的子节点的fiber
	deletions: FiberNode[] | null;

	// 优先级
	lanes: Lanes;

	// 子节点的优先级

	childLanes: Lanes;

	// 依赖
	dependencies: FiberDependencies<any> | null;
	constructor(tag: WorkTag, pendingProps: Props, key: Key) {
		// 实例

		// 标识 fiber 的类型
		this.tag = tag;
		// 类型 <div/> type: 'div'
		this.key = key || null;
		// HostComponent <div> div DOM
		// 节点对应的 dom
		this.stateNode = null;

		// FunctionComponent () => {}如果是函数组件 对应函数 类组件对应类本事
		this.type = null;

		// 构成树状结构
		this.return = null;
		this.sibling = null;
		this.child = null;
		this.index = 0;

		this.ref = null;

		// 作为工作单元
		this.pendingProps = pendingProps;
		this.memoizedProps = null;
		this.memoizedState = null; // 不同情况 状态存的 不用 可能是 reactElement
		this.updateQueue = null;

		this.alternate = null;
		// 副作用
		this.flags = NoFlags;
		this.subtreeFlags = NoFlags;
		this.deletions = null;

		this.lanes = NoLanes;
		this.childLanes = NoLanes;

		this.dependencies = null;
	}
}

export interface PendingPassiveEffects {
	unmount: Effect[]; // 存着 很多fiber 需要执行 卸载回掉函数的  effect环状链表
	update: Effect[]; //  存着 很多fiber 需要执行 卸载回掉函数和副作用回调函数的  effect环状链表
}

// 这不是 普通fiber 而是整个 应用的 Fiber节点类型
// 里面的 参数和 普通fiber 不一样 这样一个结构
// FiberRootNode.current =  hostRootFiber
// hostRootFiber.stateNode = FiberRootNode
// FiberRootNode.container  =  appDom
export class FiberRootNode {
	container: Container; // 不用宿主环境下的  container
	current: FiberNode;
	finishedWork: FiberNode | null;
	pendingLanes: Lanes; //所有未被消费的优先级lane的集合    位置上为1的就代表 该优先级对应的那个update 还为更新 如果 被调度器拿出来去 协调了 那就将 1 改为0
	suspendedLanes: Lanes;

	pingedLanes: Lanes;
	finishedLane: Lane; // 调度 协调更新完后 设置更新完的 优先级

	pendingPassiveEffects: PendingPassiveEffects; // 里面收集了 需要 需要执行副作用的 Effect

	callbackNode: CallbackNode | null; // 表示当前正在调度的函数对应的任务Task 是调度器包装返回的
	callbackPriority: Lane; // 表示上一次调度更新函数的优先级 是一个lane

	pingCache: WeakMap<Wakeable<any>, Set<Lane>> | null;

	constructor(container: Container, hostRootFiber: FiberNode) {
		this.container = container;
		this.current = hostRootFiber;
		hostRootFiber.stateNode = this;
		this.finishedWork = null;
		this.pendingLanes = NoLanes;
		this.suspendedLanes = NoLanes;
		this.pingedLanes = NoLanes;
		this.finishedLane = NoLane;

		this.callbackNode = null;
		this.callbackPriority = NoLane;

		this.pendingPassiveEffects = {
			unmount: [],
			update: []
		};

		this.pingCache = null;
	}
}

// 利用双缓冲 切换 fiber
// 双缓冲
// 显示Fiber 就是 现实 ui 对应的Fiber
// 缓冲Fiber 即将变化的Ui 对应的Fiber 也是 要拿去对比的 Fiber

// 传入一个 fiber 如果首次渲染 则新创建一个 fiber 返回
export const createWorkInProgress = (
	current: FiberNode,
	pendingProps: Props
): FiberNode => {
	// 当是 首次渲染 时  current 为当前工作取的hostRootFiber
	// 然后 取到 缓冲区的fiber  去协调 没有就创建 链接上
	// 当需要复用fiber 时  current是当前 正在协调的fiber
	let wip = current.alternate;
	if (wip === null) {
		// 首屏渲染 的话   alternate 为null
		// 就创建一个 Fiber 当做缓冲区Fiber 去 工作
		// mount
		wip = new FiberNode(current.tag, pendingProps, current.key);
		wip.stateNode = current.stateNode;

		// 互相指向
		wip.alternate = current;
		current.alternate = wip;
	} else {
		// update
		// 更新的话 那到 显示区Fiber 的 alternate 去 做为当前工作的 wip Fiber  也就是取出 缓冲区Fiber
		wip.pendingProps = pendingProps;
		wip.flags = NoFlags;
		wip.subtreeFlags = NoFlags;
		wip.deletions = null;
	}
	wip.type = current.type;
	wip.updateQueue = current.updateQueue;
	wip.child = current.child;
	wip.memoizedProps = current.memoizedProps;
	wip.memoizedState = current.memoizedState;
	wip.ref = current.ref;

	wip.lanes = current.lanes;
	wip.childLanes = current.childLanes;

	const currentDeps = current.dependencies;
	wip.dependencies =
		currentDeps === null
			? null
			: {
					lanes: currentDeps.lanes,
					firstContext: currentDeps.firstContext
			  };

	return wip;
};

// 该函数 根据传入到 ReactElement元素 创建一个 对应的Fiber
// ReactElement元素  是 jsx 通过babel 编译后执行 CreateReactElement元素的产物
// 根据不同 type 创建 不同类型Fiber
export function createFiberFromElement(element: ReactElementType): FiberNode {
	const { type, key, props, ref } = element;
	let fiberTag: WorkTag = FunctionComponent;

	if (typeof type === 'string') {
		// <div/> type: 'div'
		fiberTag = HostComponent;
	} else if (typeof type === 'object') {
		switch (type.$$typeof) {
			case REACT_PROVIDER_TYPE:
				fiberTag = ContextProvider;
				break;
			case REACT_MEMO_TYPE:
				fiberTag = MemoComponent;
				break;
			case REACT_LAZY_TYPE:
				fiberTag = LazyComponent;
				break;
			default:
				console.warn('未定义的type类型', element);
				break;
		}
	} else if (type === REACT_SUSPENSE_TYPE) {
		fiberTag = SuspenseComponent;
	} else if (typeof type !== 'function' && true) {
		console.warn('为定义的type类型', element);
	}
	const fiber = new FiberNode(fiberTag, props, key);
	fiber.type = type;
	fiber.ref = ref;
	return fiber;
}

// 创建一个Fiber
export function createFiberFromFragment(elements: any[], key: Key): FiberNode {
	const fiber = new FiberNode(Fragment, elements, key);
	return fiber;
}

export interface OffscreenProps {
	mode: 'visible' | 'hidden';
	children: any;
}

// 创建一个Fiber
export function createFiberFromOffscreen(pendingProps: OffscreenProps) {
	const fiber = new FiberNode(OffscreenComponent, pendingProps, null);
	// TODO stateNode
	return fiber;
}
